/**
 *  @file ByteStreamBody.cpp
 */
#include "IHttpBody.h"
#include "../../../common/CppMemPool.h"
#include "../../../common/UtilFuncT.h"
#include "../../../io/MemoryStream.h"

using namespace cppflib::collections;
using namespace cppflib::io;

namespace cppflib
{

namespace net
{

namespace http
{

namespace message
{


PRIVATE BinBuf * __GetBB(BaseObject * pByteBody)
{
   return static_cast<BinBuf *>(pByteBody);
}

PRIVATE MemoryStream * __GetMem(BaseObject * pByteBody)
{
   return static_cast<MemoryStream *>(pByteBody);
}

PRIVATE ArrayByte * __GetArray(BaseObject * pByteBody)
{
   return static_cast<ArrayByte *>(pByteBody);
}


ByteStreamBody::ByteStreamBody(void)
{
}

ByteStreamBody::ByteStreamBody(BinBuf *pBinBuf)
{
   this->pByteBody = pBinBuf;
   cppmempool::Retain(this->pByteBody);

   SetContentLength(pBinBuf->GetValidLength());
   SetCurReadPos(0);
}

ByteStreamBody::ByteStreamBody(MemoryStream *pMemStream)
{
   this->pByteBody = pMemStream;
   cppmempool::Retain(this->pByteBody);

   SetContentLength(pMemStream->GetBufferSize());
   SetCurReadPos(0);
   pMemStream->ResetPointer();  // reset to beginning
}

ByteStreamBody::ByteStreamBody(ArrayByte *pArrayByte)
{
   this->pByteBody = pArrayByte;
   cppmempool::Retain(this->pByteBody);

   SetContentLength(pArrayByte->GetSize());
   SetCurReadPos(0);
}

ByteStreamBody::~ByteStreamBody(void)
{
   cppmempool::Release(this->pByteBody);
}

int ByteStreamBody::Read(collections::ArrayByte &buffer)
{
   return Read(buffer, 0, static_cast<int>(buffer.GetSize()));
}

int ByteStreamBody::Read(collections::ArrayByte &buffer, int offset, int count)
{
   sz_t bytesLeft = static_cast<sz_t>(GetContentLength() - GetCurReadPos());
   if (bytesLeft == 0)
     return 0;

   if (count < 0 || offset < 0 || offset >= static_cast<int>(buffer.GetSize()))
      return 0;
  
   count = cppflib::Min<int>(count, static_cast<int>(buffer.GetSize() - offset));
   int bytesToCopy = cppflib::Min<int>(static_cast<int>(bytesLeft), count);

   if (cppflib::InstanceOf<BinBuf>(pByteBody)) {
      // BinBuf
      buffer.CopyFrom(__GetBB(pByteBody)->GetRawBuf(), static_cast<u32_t>(__GetBB(pByteBody)->GetLength()), offset, 
                      static_cast<u32_t>(GetCurReadPos()), bytesToCopy); 
   }
   else if (cppflib::InstanceOf<MemoryStream>(pByteBody)) {
      // MemoryStream
      __GetMem(pByteBody)->Read(buffer, offset, bytesToCopy);
   }
   else {
      // ArrayByte
      buffer.CopyFrom(*__GetArray(pByteBody), offset, static_cast<u32_t>(GetCurReadPos()), bytesToCopy);
   }

   AdvanceReadPos(bytesToCopy);
   return bytesToCopy;
}

int ByteStreamBody::Read()
{
   sz_t bytesLeft = static_cast<sz_t>(GetContentLength() - GetCurReadPos());
   if (bytesLeft == 0)
     return -1;

   int ret = 0;
   if (cppflib::InstanceOf<BinBuf>(pByteBody)) {
      // BinBuf
      ret = __GetBB(pByteBody)->GetRawBuf()[GetCurReadPos()] & 0xff;
   }
   else if (cppflib::InstanceOf<MemoryStream>(pByteBody)) {
      // MemoryStream
      ret = __GetMem(pByteBody)->Read();
   }
   else {
      // ArrayByte
      ret = __GetArray(pByteBody)->GetRawPtr()[GetCurReadPos()] & 0xff;
   }

   AdvanceReadPos(1);
   return ret;
}


} // end of namespace message

} // end of namespace http

} // end of namespace net

} // end of namespace cppflib

